﻿#include <algorithm>
#include <gtest/gtest.h>
#include <iostream>
#include <vector>

#include <xy/math/tensor.h>
#include <xy/utils/output.h>

using namespace std;
using namespace xy;
using namespace xy::math;

TEST(TestTensor, basis)
{
    tensor<3, double> t(3, {
                               0, 1,  2,  3,  4,  5,  6,  7,  8,

                               9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
                           });

    EXPECT_EQ(t.base(), 3);
    EXPECT_EQ(t.size(), 27);

    int i = 0;
    do
    {
        std::cout << t.at_index() << " ";
        i++;
    } while (t.move_index());

    {
        int i = 0;
        do
        {
            EXPECT_EQ(t.at_index(), i++);
        } while (t.move_index());
    }

    {
        auto t2 = t + 1;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), i++ + 1);
        } while (t2.move_index());
    }

    {
        auto t2 = t - 1;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), i++ - 1);
        } while (t2.move_index());
    }

    {
        auto t2 = t * 2;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), i++ * 2);
        } while (t2.move_index());
    }

    {
        auto t2 = t / 2;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), i++ / 2.0);
        } while (t2.move_index());
    }

    {
        t += 1;
        int i = 0;
        do
        {
            EXPECT_EQ(t.at_index(), i++ + 1);
        } while (t.move_index());
    }

    {
        t -= 1;
        int i = 0;
        do
        {
            EXPECT_EQ(t.at_index(), i++);
        } while (t.move_index());
    }

    {
        t *= 2;
        int i = 0;
        do
        {
            EXPECT_EQ(t.at_index(), i++ * 2);
        } while (t.move_index());
    }

    {
        t /= 2;
        int i = 0;
        do
        {
            EXPECT_EQ(t.at_index(), i++);
        } while (t.move_index());
    }

    {
        auto t2 = t + t;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), i++ * 2);
        } while (t2.move_index());
    }

    {
        auto t2 = t - t;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), 0);
        } while (t2.move_index());
    }

    {
        auto t2 = -t;
        int i = 0;
        do
        {
            EXPECT_EQ(t2.at_index(), -i);
            i++;
        } while (t2.move_index());
    }
}

TEST(TestTensor, advance)
{
    tensor<3, int> t(
        3, {
               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
           });
    tensor<1, int> t1(3, {1, 2, 3});
    tensor<2, int> t2(3, {
                             0,
                             1,
                             2,
                             3,
                             4,
                             5,
                             6,
                             7,
                             8,
                         });

    // std::cout << t.component<2>(0).flatten() << std::endl;
    // std::cout << t.component<2>(1).flatten() << std::endl;
    // std::cout << t.component<2>(2).flatten() << std::endl;
    // std::cout << t.component<1>(0).flatten() << std::endl;
    // std::cout << t.component<1>(1).flatten() << std::endl;
    // std::cout << t.component<1>(2).flatten() << std::endl;

    // std::cout << (t * t1).flatten() << std::endl;
    // std::cout << (t * t2).flatten() << std::endl;
    // std::cout << (t * t) << std::endl;

    // t.move_index(0, 1);
    // t.move_index(1, 1);
    // t.move_index(2, 1);
    // std::cout << t.cell().flatten() << std::endl;

    // tensor<1, int> t3(3, {1, 2, 1});
    // std::cout << power<3>(t3).flatten() << std::endl;
}